package campus.aiit.ssl.config;

import com.iflytek.uaac.client.cache.ClientResourceCache;
import com.iflytek.uaac.client.constant.UaacConstant;
import com.iflytek.uaac.client.filter.*;
import com.iflytek.uaac.client.rest.context.UaacServiceContext;
import com.iflytek.uaac.client.util.RegexUrlPathMatcher;
import com.iflytek.uaac.client.util.UrlMatcher;
import com.iflytek.uaac.client.util.UrlParamUtil;
import org.apache.commons.lang.StringUtils;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.util.AbstractConfigurationFilter;
import org.jasig.cas.client.util.AssertionThreadLocalFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.HttpMethod;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

/**
 * 重写了 {@link com.iflytek.uaac.client.rest.filter.FilterChainProxy} 类，
 * 重写了其 init 方法
 * 主要是修改 init时读取配置文件的问题
 */
public class LocalizedFilterChainProxy extends AbstractConfigurationFilter {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private Filter[] filters;
    private UrlMatcher urlMatcher = new RegexUrlPathMatcher();
    private UaacConstant uaacConstant;
    private String casAuthAjaxContext;
    private String userTypeConfig;

    public LocalizedFilterChainProxy() {
    }

    @Override
    public void destroy() {
        for (Filter filter : this.filters) {
            if (filter != null) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Destroying Filter defined in ApplicationContext: '" + filter.toString() + "'");
                }

                filter.destroy();
            }
        }

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        if (response instanceof HttpServletResponse) {
            // 用于兼容IE，基本没用了
            ((HttpServletResponse)response).setHeader("P3P", "CP=CAO PSA OUR IDC DSP COR ADM DEVi TAIi PSD IVAi IVDi CONi HIS IND CNT");
        }
        HttpSession Session = ((HttpServletRequest) request).getSession();
        String userId =(String) Session.getAttribute("userId");
        System.out.println("UserId:"+userId);
        System.out.println("haveUserId:"+!(userId == null));
//        System.out.println("haveUserId:"+userId);||httpRequest.getServletPath().equals("/propertyLogin")||(!userId.equals(null))
        if (!this.isResource(httpRequest.getServletPath())||httpRequest.getServletPath().equals("/propertyLogin")||!(userId == null)) {
            chain.doFilter(request, response);
        } else {
            FilterInvocation fi = new FilterInvocation(request, response, chain);   //根据原request、response、chain，构建一个新的Invocation对象
            if (this.filters.length == 0) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug(fi.getRequestUrl() + " has an empty filter list");
                }

                chain.doFilter(request, response);
            } else {
                VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, this.filters);   // 根据Invocation + client filters，构建新的Chain；替代了原Chain
                virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
            }
        }
    }

    private boolean isResource(String url) {
        String url1;
        if (this.uaacConstant.isUseSsoAuthority()) {
            Iterator ite = ClientResourceCache.getAllClientResourceCache().keySet().iterator();

            while(ite.hasNext()) {
                url1 = (String)ite.next();
                if (this.urlMatcher.pathMatchesUrl(this.urlMatcher.compile(UrlParamUtil.getResourceUrl(url1)), UrlParamUtil.getUrl(url))) {
                    return true;
                }
            }

            return false;
        } else {
            String[] urls;
            int var4;
            int var5;
            String[] var6;
            if (StringUtils.isNotBlank(this.uaacConstant.getNoAuthorizationUrls())) {
                urls = StringUtils.split(this.uaacConstant.getNoAuthorizationUrls(), ",");
                var6 = urls;
                var5 = urls.length;

                for(var4 = 0; var4 < var5; ++var4) {
                    url1 = var6[var4];
                    if (this.urlMatcher.pathMatchesUrl(this.urlMatcher.compile(UrlParamUtil.getResourceUrl(url1)), UrlParamUtil.getUrl(url))) {
                        return false;
                    }
                }
            }

            if (StringUtils.isNotBlank(this.uaacConstant.getAuthorizationUrls())) {
                urls = StringUtils.split(this.uaacConstant.getNoAuthorizationUrls(), ",");
                var6 = urls;
                var5 = urls.length;

                for(var4 = 0; var4 < var5; ++var4) {
                    url1 = var6[var4];
                    if (this.urlMatcher.pathMatchesUrl(this.urlMatcher.compile(UrlParamUtil.getResourceUrl(url1)), UrlParamUtil.getUrl(url))) {
                        return true;
                    }
                }
            }

            return true;
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        UaacConstant uaacConstant = new UaacConstant();
        Properties p = new Properties();
        this.userTypeConfig = filterConfig.getInitParameter("userTypeConfig");
        String uaacConfig = filterConfig.getInitParameter("uaac-config");
        if (StringUtils.isNotBlank(uaacConfig)) {
            try {
                if (uaacConfig.endsWith("xml")) {
                    p.loadFromXML(new FileInputStream(uaacConfig));
                } else {
                    p.load(new FileInputStream(uaacConfig));
                }
            } catch (InvalidPropertiesFormatException var15) {
                this.logger.warn("外部配置文件格式错误：" + uaacConfig);
                var15.printStackTrace();
            } catch (FileNotFoundException var16) {
                this.logger.warn("外部配置文件不存在：" + uaacConfig);
                var16.printStackTrace();
            } catch (IOException var17) {
                this.logger.warn("外部配置文件读取错误：" + uaacConfig);
                var17.printStackTrace();
            }
        }

        URL url;
        if (p.isEmpty()) {
            /*
             *  XXX 这里相较源代码改了一下（源码 打包后，无法读取到配置文件uaac-client-rest.xml，需要改为字节流来读取）
             *  源代码： url = this.getClass().getClassLoader().getResource("/uaac-client-rest.xml");
             *  本地运行没问题，但打包运行失败： url = this.getClass().getClassLoader().getResource("uaac-client-rest.xml");
             *  改成如下的方式就可以，要用字节流来读取
             */
            // url = this.getClass().getClassLoader().getResource("uaac-client-rest.xml");
            InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("uaac-client-rest.xml");

            try {
                // 此处也修改了
                if (resourceAsStream!=null){
                    p.loadFromXML(resourceAsStream);
                }
                /*if (url != null) {
                    p.loadFromXML(new FileInputStream(url.getFile()));
                }*/
            } catch (InvalidPropertiesFormatException var11) {
                this.logger.warn("类路径中配置文件格式错误：uaac-client-rest.xml");
                var11.printStackTrace();
            } catch (FileNotFoundException var12) {
                this.logger.warn("类路径中配置文件不存在：uaac-client-rest.xml");
                var12.printStackTrace();
            } catch (IOException var13) {
                this.logger.warn("类路径中配置文件读取错误：uaac-client-rest.xml");
                var13.printStackTrace();
            } catch (Exception var14) {
                this.logger.warn("类路径中配置文件读取错误：uaac-client-rest.xml");
                var14.printStackTrace();
            }
        }

        if (p.isEmpty()) {
            url = this.getClass().getClassLoader().getResource("/uaac-client-rest.properties");

            try {
                if (url != null) {
                    p.load(new FileInputStream(url.getFile()));
                }
            } catch (InvalidPropertiesFormatException var7) {
                this.logger.warn("类路径中配置文件格式错误：uaac-client-rest.properties");
                var7.printStackTrace();
            } catch (FileNotFoundException var8) {
                this.logger.warn("类路径中配置文件不存在：uaac-client-rest.properties");
                var8.printStackTrace();
            } catch (IOException var9) {
                this.logger.warn("类路径中配置文件读取错误：uaac-client-rest.properties");
                var9.printStackTrace();
            } catch (Exception var10) {
                this.logger.warn("类路径中配置文件读取错误：uaac-client-rest.properties");
                var10.printStackTrace();
            }
        }

        if (p.isEmpty()) {
            this.logger.error("uaac-client配置文件加载失败！");
        }

        uaacConstant.setAppAuthCode(p.getProperty("uaac.client.appAuthCode"));
        uaacConstant.setAppCode(p.getProperty("uaac.client.appCode"));
        uaacConstant.setAppSecurityCode(p.getProperty("uaac.client.appSecurityCode"));
        uaacConstant.setCasClientContext(p.getProperty("cas.client.context"));
        uaacConstant.setCasContext(p.getProperty("cas.context"));
        uaacConstant.setCasValidContext(p.getProperty("cas.valid.context"));
        uaacConstant.setCasContextLogin(p.getProperty("cas.context.login"));
        uaacConstant.setCasContextLogout(p.getProperty("cas.context.logout", "/logout"));
        uaacConstant.setResturl(p.getProperty("uaac.service.url"));
        uaacConstant.setSignVerrifyurl(p.getProperty("uaac.service.signVerrifyurl"));
        uaacConstant.setUseSsoAuthority(Boolean.valueOf(p.getProperty("uaac.useSso.Authority", "false")));
        uaacConstant.setUseSsoAuthentication(Boolean.valueOf(p.getProperty("uaac.useSso.Authentication", "false")));
        uaacConstant.setAuthorizationUrls(p.getProperty("uaac.authorizationUrls"));
        uaacConstant.setNoAuthorizationUrls(p.getProperty("uaac.noAuthorizationUrls"));
        UaacServiceContext.init(uaacConstant);
        this.uaacConstant = uaacConstant;
        this.casAuthAjaxContext = filterConfig.getInitParameter("casAuthAjaxContext");
        this.filters = this.obtainAllDefinedFilters(uaacConstant);

        for(int i = 0; i < this.filters.length; ++i) {
            if (this.filters[i] != null) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Initializing Filter defined in ApplicationContext: '" + this.filters[i].toString() + "'");
                }

                this.filters[i].init(filterConfig);
            }
        }

    }

    private Filter[] obtainAllDefinedFilters(UaacConstant uaacConstant) {
        Set<Filter> list = new LinkedHashSet();
        SingleSignOutFilter ssof = new SingleSignOutFilter();
        ssof.setCasServerUrlPrefix(uaacConstant.getCasContext());
        ssof.setIgnoreInitConfiguration(true);
        list.add(ssof);
        AuthenticationFilter authenticationFilter = new AuthenticationFilter();
        authenticationFilter.setCasServerLoginUrl(uaacConstant.getCasContext() + uaacConstant.getCasContextLogin());
        authenticationFilter.setServerName(uaacConstant.getCasClientContext());
        authenticationFilter.setCasAuthAjaxContext(this.casAuthAjaxContext);
        authenticationFilter.setIgnoreInitConfiguration(true);
        list.add(authenticationFilter);
        Cas20ProxyReceivingTicketValidationFilter validationFilter = new Cas20ProxyReceivingTicketValidationFilter();
        validationFilter.setUseSession(true);
        validationFilter.setServerName(uaacConstant.getCasClientContext());
        validationFilter.setRedirectAfterValidation(true);
        validationFilter.setMillisBetweenCleanUps(60000);
        validationFilter.setIgnoreInitConfiguration(true);
        Cas20ServiceTicketValidator cas20ServiceTicketValidator = null;
        if (StringUtils.isNotBlank(uaacConstant.getCasValidContext())) {
            cas20ServiceTicketValidator = new Cas20ServiceTicketValidator(uaacConstant.getCasValidContext());
        } else {
            cas20ServiceTicketValidator = new Cas20ServiceTicketValidator(uaacConstant.getCasContext());
        }

        validationFilter.setTicketValidator(cas20ServiceTicketValidator);
        list.add(validationFilter);
        list.add(new AssertionThreadLocalFilter());
        list.add(new HttpServletRequestWrapperFilter());
        if (uaacConstant.isUseSsoAuthority()) {
            DecisionFilter decisionFilter = new DecisionFilter();
            decisionFilter.setUaacConstant(UaacServiceContext.getUaacConstant());
            decisionFilter.setUaacService(UaacServiceContext.getUaacService());
            decisionFilter.setUserService(UaacServiceContext.getUserService());
            list.add(decisionFilter);
        }

        if (StringUtils.isNotBlank(this.userTypeConfig)) {
            list.add(new UserTypeFilter());
        }

        return (Filter[])list.toArray(new Filter[0]);
    }

    public UaacConstant getUaacConstant() {
        return this.uaacConstant;
    }

    public void setUaacConstant(UaacConstant uaacConstant) {
        this.uaacConstant = uaacConstant;
        UaacServiceContext.init(uaacConstant);
        this.filters = this.obtainAllDefinedFilters(uaacConstant);
    }
}
